--上传文件模块：
--
-- 使用说明：
-- 加载此模块， local success, msg, origin_filename, extname, path, filename = uploader({dir = '/home/webserver/cms/www'})
-- 返回参数说明：
--  success：文件是否上传成功，msg：上传失败后的原因，origin_filename：原来的文件名称，extname：后缀名称，path：上传文件的绝对路径
--  filename：上传后的文件名称
local upload = require("resty.upload")
local resty_random = require "resty.random"
local str = require "resty.string"


local sfind = string.find
local match = string.match
local ngx_var = ngx.var


--获取文件扩展名
local function getextension(filename)
    return filename:match(".+%.(%w+)$")
end

--上传文件方法
local function _multipart_formdata(config)
    local form, err = upload:new(config.chunk_size)
    if not form then
        ngx.log(ngx.ERR, "failed to new upload: ", err)
        ngx.exit(500)
    end
    form:set_timeout(config.recieve_timeout)
    --这里的得到唯一名称
    local random = resty_random.bytes(16)
    --使用随机数生成唯一随机数名称
    local unique_name = str.to_hex(random)
    --后续加上按 年/月/日/unique_name 的方式存储

    local success, msg = false, ""
    local key,filetype
    local file, origin_filename, filename, path, extname, err
    while true do
        local typ, res, err = form:read()

        if not typ then
            success = false
            msg = "failed to read"
            ngx.log(ngx.ERR, "failed to read: ", err)
            return success, msg
        end

        if typ == "header" then
            if res[1] == "Content-Disposition" then
                key = match(res[2], "name=\"(.-)\"")
                origin_filename = match(res[2], "filename=\"(.-)\"")
            elseif res[1] == "Content-Type" then
                filetype = res[2]
            end

            if origin_filename and filetype then
                if not extname then
                    extname = getextension(origin_filename)
                end

                --这里是文件类型判断。后面做成可配置数组
                if extname ~= "png" and extname ~= "jpg" and extname ~= "jpeg"  and extname ~= "bmp"  and extname ~= "gif" then
                    success = false
                    msg = "not allowed upload file type"
                    ngx.log(ngx.ERR, "not allowed upload file type:", origin_filename)
                    return success, msg
                end

                filename = unique_name .. "." .. extname
                path = config.dir.. "/" .. filename

                file, err = io.open(path, "w+")

                if err then
                    success = false
                    msg = "open file error"
                    ngx.log(ngx.ERR, "open file error:", err)
                    return success, msg
                end
            end

        elseif typ == "body" then
            if file then
                file:write(res)
                success = true
            else
                success = false
                msg = "upload file error22"
                ngx.log(ngx.ERR, "upload file error, path:", path)
                return success, msg
            end
        elseif typ == "part_end" then
            file:close()
            file = nil
        elseif typ == "eof" then
            break
        else
            -- do nothing
        end
    end

    return success, msg, origin_filename, extname, path, filename
end

--暴露给外面的外部方法
--config = {dir="/temp",chunk_size = 4096,recieve_timeout = 20000}
-- dir 文件保存目录，chunk_size 分片大小 ，recieve_timeout，超时时间：20000
local function uploader(config)
    if ngx_var.request_method == "POST" then
        local get_headers = ngx.req.get_headers()
        local header = get_headers['Content-Type']
        if header then
            local is_multipart = sfind(header, "multipart")
            if is_multipart and is_multipart>0 then
                config = config or {}
                config.dir = config.dir or "/tmp"
                config.chunk_size = config.chunk_size or 4096
                config.recieve_timeout = config.recieve_timeout or 20000 -- 20s
                local success, msg, origin_filename, extname, path, filename = _multipart_formdata(config)
                return success, msg, origin_filename, extname, path, filename
            end
        end
    end
end

return uploader